package com.gopay.cashier.web.controller;

import com.gopay.cashier.common.exception.WebException;
import com.gopay.cashier.common.util.qrcode.QRCodeUtil;
import com.gopay.cashier.domain.bean.AcctBean;
import com.gopay.cashier.domain.bean.ExpressCardInfo;
import com.gopay.cashier.domain.bean.LoginUser;
import com.gopay.cashier.domain.bean.PayChannelDtlBean;
import com.gopay.cashier.domain.bean.PayChannelWayBean;
import com.gopay.cashier.service.CaCertService;
import com.gopay.cashier.service.PersonUsedQuotaService;
import com.gopay.cashier.service.gsrt.GsrtService;
import com.gopay.cashier.web.command.BankPayWay;
import com.gopay.cashier.web.command.OrderInfo;
import com.gopay.cashier.web.command.PayInfoCommand;
import com.gopay.cashier.web.utils.BisBankBusinessProdConvertUtil;
import com.gopay.cashier.web.utils.CashierConfig;
import com.gopay.cashier.web.utils.PayPwdQuestionsInfo;
import com.gopay.common.cipher.utils.LoggerMaskUtils;
import com.gopay.common.constants.SubAccountConstants;
import com.gopay.common.constants.YnFlag;
import com.gopay.common.constants.cust.CustCaCertConstants;
import com.gopay.common.constants.cust.CustPersonInfoConstants;
import com.gopay.common.constants.cust.UserInfoConstants;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.constants.trans.GatewaySource;
import com.gopay.common.constants.trans.OrderFeePayer;
import com.gopay.common.constants.trans.PayAuthType;
import com.gopay.common.constants.trans.PayChannel;
import com.gopay.common.constants.trans.PayChannelType;
import com.gopay.common.constants.trans.TxnStaCode;
import com.gopay.common.constants.trans.UserType;
import com.gopay.common.constants.txncd.IntTxnCd;
import com.gopay.common.cps.dao.order.CpsGeneralReceiptOrderQueryDAO;
import com.gopay.common.domain.UserInfo;
import com.gopay.common.domain.acps.AcctProd;
import com.gopay.common.domain.acps.model.AcctMastBean;
import com.gopay.common.domain.cps.CpsGenMainOrder;
import com.gopay.common.domain.cps.CpsGenReceiptOrder;
import com.gopay.common.domain.cust.CustCaCert;
import com.gopay.common.domain.cust.CustCorpInfo;
import com.gopay.common.domain.cust.CustPersonInfo;
import com.gopay.common.domain.ep.EpCardBin;
import com.gopay.common.domain.ep.EpCardBindInfoVo;
import com.gopay.common.domain.gopay.GopayAllCustInfo;
import com.gopay.common.domain.pg.PgGenOrderTransDtl;
import com.gopay.common.domain.poundage.PoundageRes;
import com.gopay.common.domain.rcs.RcsAntiPhishViolateLog;
import com.gopay.common.domain.user.identify.vo.PersonTypeQuotaVo;
import com.gopay.common.exception.GopayException;
import com.gopay.common.rcs.bean.UserDicision;
import com.gopay.common.security.encryptiondecryption.Decrypt;
import com.gopay.common.user.dao.AllCustInfoQueryDAO;
import com.gopay.common.user.manager.DicCustProfessionQueryManager;
import com.gopay.common.user.manager.PersonIdentifyManager;
import com.gopay.common.util.*;
import com.gopay.remote.cps.expresspay.EpBankCardRemoteService;
import com.gopay.remote.order.MainOrderField;
import com.gopay.remote.order.Tran01813OrderCheckAndUpdateRemoteService;
import com.gopay.remote.solution.vo.PayChannelDtlInfo;
import com.gopay.remote.user.UserRemoteService;
import net.sf.json.JSONObject;
import org.apache.commons.codec.binary.*;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Administrator
 * @CashierController
 */
@Controller
public class PayChannelInfoController extends BaseController {
    protected final static Log logger = LogFactory.getLog(PayChannelInfoController.class);

    private static final String CAS_URL = CashierConfig.get(CashierConfig.CAS_SERVER_URL);
    
    private static final String CASHIER_URL = CashierConfig.get(CashierConfig.CASHIER_URL);
    
    private static final String PORTAL_URL = CashierConfig.get(CashierConfig.PORTAL_URL);
    //是否启用指纹数据采集  0：不启用  1：启用
    private static final String ENABLE_FINGERINFO = CashierConfig.get(CashierConfig.ENABLE_FINGERINFO);

    @Value("#{webProperties['wallet.app.url']}")
    private String walletAppUrl;

    @Autowired
    private CpsGeneralReceiptOrderQueryDAO cpsGeneralReceiptOrderQueryDAO;

    @Resource(name = "epBankCardService")
    private EpBankCardRemoteService epBankCardService;

    @Resource(name="dicCustProfessionQueryManager")
    private DicCustProfessionQueryManager dicCustProfessionQueryManager;
    
    @Resource(name = "allCustInfoQueryDAO")
    protected AllCustInfoQueryDAO allCustInfoQueryDAO;
    

    @Resource(name="gsrtService")
    private GsrtService gsrtService;
    
    @Resource(name = "personIdUsedQuotaService")
    private PersonUsedQuotaService personIdUsedQuotaService;

    @Resource(name = "caCertService")
    private CaCertService caCertService;
    
	@Resource(name = "personIdentifyManager")
    private PersonIdentifyManager personIdentifyManager;
    
	@Resource(name = "userRemoteService")
    private UserRemoteService userRemoteService;

	@Resource(name = "tran01813OrderCheckAndUpdateService")
	private Tran01813OrderCheckAndUpdateRemoteService tran01813OrderCheckAndUpdateRemoteService;
	
    @RequestMapping("/pay/info.shtml")
    public ModelAndView execute(PayInfoCommand command) throws GopayException {
        printRequest();
        
         CpsGenMainOrder order = getMainOrder(getRequest().getParameter("orderId"), true);
        
        CustCorpInfo cust = custCorpInfoService.get(order.getMerId());
        // 校验
        validate(command, order, cust);
        // 防钓鱼
        ModelAndView mav = ipCheckDecison(command, order);
        if (null != mav) return mav;
        // 刷新登录用户
        command.setInc(isInchargeOrder(order) ? PayInfoCommand.INCHARGE_ORDER : "n");
        //直连银行；
        if (isDirectBankPay(order)) {
           if(StringUtils.equals(PayChannel._01.value,order.getPayChannel()) || StringUtils.equals(PayChannel._51.value,order.getPayChannel())){
                //个人网银、企业网银-直连模式
               printHeader();

               String orderToken = (String) getRequest().getSession().getAttribute(order.getGopayOrderId() + getRequest().getParameter(GOPAY_ORDER_KEY));
               if (StringUtils.isBlank(orderToken) || !"0".equals(orderToken)) {
                   //抛出异常 认为是非正常访问
                   throw new WebException(ProcCodeConstants.PROC_CODE_100E5326);
               }

               //防钓鱼校验 add by  dongdh 20180308
               ModelAndView check = checkAntiPhishForDirect(command,"/pay/info.shtml?orderKey="+getRequest().getParameter("orderKey")+"&orderId="+order.getGopayOrderId());
               if(check != null)
                   return check;

               getRequest().getSession().removeAttribute(order.getGopayOrderId() + getRequest().getParameter(GOPAY_ORDER_KEY));

               updateDirectBankPayOrder(command, order);
               /**** add by sh.jiao 20170920 增加云账户子账户收款修改关联订单交易金额，手续费金额等字段更新逻辑 start ****/
               /*if(IntTxnCd._01813.value.equals(order.getGopayIntTxnCd())) {
                   String resultCode = tran01813OrderCheckAndUpdateRemoteService.checkAndUpdateOrder(order.getGopayOrderId());
                   if (!ProcCodeConstants.PROC_CODE_000S1000.equals(resultCode)) {
                       throw new WebException(resultCode);
                   }
               }*/
               /**** add by sh.jiao 20170920 增加云账户子账户收款修改关联订单交易金额，手续费金额等字段更新逻辑 end ****/
               return directBankPayPage(command);
            }
        }
        return next(order,command);
    }
    
    /**
     * 处理清算方案
     * @param order
     * @param payWay
     */
    private void dealPayChannels(CpsGenMainOrder order,PayChannelWayBean payWay){
        String recvCustId = order.getMainRecvCustId();
        GopayAllCustInfo custInfo=allCustInfoQueryDAO.getAllCustInfoByCustId(recvCustId);
        
        if("1".equals(custInfo.getCustType())){
            //个人客户
        	
        }
        else if("2".equals(custInfo.getCustType())){
            //企业客户
            
            //充值
            if(IntTxnCd._00500.value.equals(order.getGopayIntTxnCd())){    
                List<PayChannelDtlBean> pcdList=payWay.getPayChannelList();
                PayChannelDtlBean pcd=null;
                for(PayChannelDtlBean bean : pcdList){
                    if(StringUtils.equals(PayChannelType.OUTSTLM_PAY.value, bean.getPayChannelType())){
                        pcd=bean;
                        break;
                    }
                }
                               
                if(pcd!=null){
                    Map<String, List<PayChannelDtlInfo>> map = pcd.getBankCodes();
                    List<PayChannelDtlInfo> dtlInfoList = map.get(PayChannel._01.value);
                    if(dtlInfoList!=null && dtlInfoList.size()>0){
                        for(int i=0;i<dtlInfoList.size();){
                            if(!dtlInfoList.get(i).getPersonal()){
                                //来自通用方案则排除
                                dtlInfoList.remove(i);                                
                            }else {
                                i++;
                            }
                        }
                        
                    }
                }
            }
            
            
            
        }//else
        
    }
    
    private ModelAndView  next(CpsGenMainOrder order,PayInfoCommand command) throws WebException{
        try {
            prepareRSA();
        } catch (Exception e) {
            throw new WebException(ProcCodeConstants.PROC_CODE_100F1002);
        }
        HttpServletRequest request = getRequest();
    	String inchargeFlag = command.getInc();
    	String ch = command.getCh();
    	LoginUser loginUser = getLoginUser();
    	 ModelAndView mav = new ModelAndView();
    	 if(null != loginUser){
    	     String isFirstLogin = (String) SecurityUtils.getSubject().getSession().getAttribute("isFirstLogin");
             mav.addObject("isFirstLogin",isFirstLogin);
             mav.addObject("login","1");//用户是否登录：0未登录,1:已登录
    	 }else{
    	     mav.addObject("login","0");
    	 }

    	 /*通用分账  added by Chenyu Li at 2018/3/10 start*/
    	 //如果是通用分账，取平台的交易方案
        PayChannelWayBean payWay;
        if(isSplit(order)){
            payWay = soluBisPayChannelService.getSoluBisPayChannel(order.getGopayIntTxnCd(), order.getOtherAcct());
        }else{
            payWay = soluBisPayChannelService.getSoluBisPayChannel(order.getGopayIntTxnCd(), getAcctId(order));
        }
    	 /*通用分账  added by Chenyu Li at 2018/3/10 end*/

    	/**
    	 * 如果网关来源为09，G商融通，则用平台账户去获取交易方案
    	 */
    	if(StringUtils.equals(order.getGatewaySource(), GatewaySource.GATEWAY_SOURCE_09.value)){
    		AcctMastBean ptAcct = getPTAcctBean(order.getMerId());
    		if(ptAcct != null){
    			payWay = soluBisPayChannelService.getSoluBisPayChannel(order.getGopayIntTxnCd(), ptAcct.getAcctId());
    		}
    	}
    	//处理清算方案 add by fanghw 20151116
    	dealPayChannels(order,payWay);
    	
    	PgGenOrderTransDtl transDtl = pgGeneralOrderTransDtlQueryManager.get(order.getTransDtlSq());
    	
    	Object idInfoNotEq = getRequest().getSession().getAttribute("idInfoNotEq");
    	if (idInfoNotEq != null) {
    		mav.addObject("idInfoNotEq", idInfoNotEq.toString());
    		getRequest().getSession().removeAttribute("idInfoNotEq");
    	}
    	 /****云账户需要在企业网银页面显示异地支付收取手续费的提示信息  20160627 jiaoshuai start****/
        if(order.getMainPayAcctProdCode() != null &&
                ("CLOUD".equals(order.getMainPayAcctProdCode()) ||"SUBCLOUD".equals(order.getMainPayAcctProdCode()))) {
            mav.addObject("maiPayAcctProdCode", order.getMainPayAcctProdCode());
        }
        /****云账户需要在企业网银页面显示异地支付收取手续费的提示信息  20160627 jiaoshuai end****/
    	
    	if(loginUser !=null){
//            PayChannelDtlBean expressBean = payWay.getPayChannelDtl(PayChannelType.CREDIT_EXPRESS_PAY.value);
            PayChannelDtlBean gopayBean = payWay.getPayChannelDtl(PayChannelType.GFB_PAY.value);
            /*if(expressBean!=null && !StringUtils.equals(loginUser.getUser().getUserType(), UserInfoConstants.USER_TYPE_PERSON)){
                //企业用户登录，去掉快捷支付
                payWay.getPayChannelList().remove(expressBean);
                logger.info("corp login remove expresspay channel");
            }*/
            if(gopayBean!=null &&
                    (IntTxnCd._00100.value.equals(order.getGopayIntTxnCd())
                    ||IntTxnCd._01813.value.equals(order.getGopayIntTxnCd()))){
                payWay.getPayChannelList().remove(gopayBean);
                logger.info("login remove gopay channel");
            }
            
            // 增加校验使用动态口令卡的权限
    		String custId = getLoginUser().getUser().getCustId();
    		boolean flag = userDcPwdManager.getDCAuth(custId);
    		if (flag) {
    			mav.addObject("haveDcAuth", "1");// 1表示有吧
    		}
    		// end
            
    		//快捷支付身份验证版  update  by dongdh 20160318
    		if(loginUser != null){
    			//取custid 和type判断  拿person用户的用户名和身份信息 进行比对
    			
    			if (transDtl != null) {
    				if (StringUtils.isNotBlank(transDtl.getBuyerRealCertNo())
    	        			&& StringUtils.isNotBlank(transDtl.getBuyerRealName())
    	        			&& StringUtils.isEmpty(transDtl.getBuyerRealBankAcctNum()) //并且没上传卡号
    						) {
    	        		//如果 上送姓名和身份证号 同时存在
    					if (loginUser.getUser().getUserType().equals(UserType.Person.value)) {
    	    				//个人登录
    						CustPersonInfo personInfo = custPersonInfoQueryManager.get(loginUser.getUser().getCustId());
    						if (!StringUtils.equals(personInfo.getCertNo(), transDtl.getBuyerRealCertNo()) 
    								||
    								!StringUtils.equals(personInfo.getCustName(), transDtl.getBuyerRealName())) {
    							
    							//删除登录信息
    			                
    							logger.info("交易身份信息与已登录信息不一致！orderid=" + order.getGopayOrderId());
    							///throw new WebException(ProcCodeConstants.PROC_CODE_100E6083);
    							//mav.addObject("idInfoNotEq", "true"); //登录信息不一致 进行提示
    							mav.setViewName("redirect:/pay/info.shtml?"+GOPAY_ORDER_ID+"="+order.getGopayOrderId());
    							SecurityUtils.getSubject().logout();
    							getRequest().getSession().setAttribute("idInfoNotEq", "true");
    							return  mav;
    						}
    					}
    	        	}
    			}
            }
    		
        }
    	loginUser = getLoginUser();
        DecimalFormat f = new DecimalFormat("0.00");
        String payCustId = loginUser==null?null:loginUser.getUser().getCustId();

        PayChannelDtlBean gopayBean = payWay.getPayChannelDtl(PayChannelType.SCAN_PAY.value);
        if(gopayBean!=null && IntTxnCd._00100.value.equals(order.getGopayIntTxnCd())){
            List<PayChannelDtlInfo> payChannelDtlInfos = gopayBean.getBankCodes().get(PayChannel._16.value);
            mav.addObject("payChannelDtlInfos", payChannelDtlInfos);
            // add by jianglijun 20171201 为了页面展示样式 增加payChannel长度
            mav.addObject("payChannelDtlInfosLength", payChannelDtlInfos.size());
        }

        mav.addObject(GOPAY_ORDER_ID, order.getGopayOrderId());
        mav.addObject("payWayBean", payWay);

        // 标记是否充值交易。
        mav.addObject("inc", inchargeFlag);
        mav.addObject("incUrl", CashierConfig.get(CashierConfig.CASHIER_INCHARGE_REDIRECT_INDEX)+"?acct="+order.getMainRecvAcct());
        
        //如果是G商融通发起的充值交易，设置“返回充值页面”的超链接为上一页
        /*if(StringUtils.equals(order.getGatewaySource(), GatewaySource.GATEWAY_SOURCE_09.value)){
        	mav.addObject("incUrl", "javascript:history.go(-1);");
        }*/
//        mav.addObject("hideIndivBank", hideIndivBank);

        if(isP2P(order)){
            String p2pLoginEmail = "";
            String custId = cpsGpContractInfoDAO.getByContractNo(order.getRemark1()).getExcluCustId();
            CustPersonInfo person = custPersonInfoQueryManager.get(custId);
            if(StringUtils.equals(person.getRegType(),"02")){
                p2pLoginEmail = person.getCustMob();
            }else{
                p2pLoginEmail = person.getEmail();
            }
            //已登录用户不是当前应当登录的用户，强制退出
            if(loginUser!=null && !StringUtils.equals(loginUser.getUser().getCustId(),custId)){
                mav.setViewName("redirect:/pay/info.shtml?"+GOPAY_ORDER_ID+"="+order.getGopayOrderId());
                SecurityUtils.getSubject().logout();
                return mav;
            }
            mav.addObject("p2pLoginEmail", p2pLoginEmail);
        }
        OrderInfo orderInfo = getOrderInfo(order.getGopayOrderId());
        mav.addObject("order", orderInfo);
        if(payCustId!=null){
        	String userType = loginUser.getUser().getUserType();
        	String custName = "";
        	String isRealNameCertify = CustPersonInfoConstants.REAL_NAME_CERTIFY_YES;
        	 if(UserType.Person.value.equals(userType)){
         		CustPersonInfo payCust = custPersonInfoQueryManager.get(payCustId);
         		custName = payCust.getCustName();
         		isRealNameCertify = payCust.getIsRealNameCertify();
         		
         		/* 个人用户类别限额提示  update by zhaojunting 20160620 增加用户类别余额提示 */
                UserInfo userInfo = null;
                if(null != loginUser){
                	userInfo = loginUser.getUser();
                }  
                if(null != userInfo && UserInfoConstants.USER_TYPE_PERSON.equals(userInfo.getUserType()) && CustPersonInfoConstants.REAL_NAME_CERTIFY_YES.equals(isRealNameCertify)){
                	String procCode = getCheckThreeCode(userInfo.getUserId(), userInfo.getCustId(), order.getMerTxnAmt());
                	if(null != procCode){
                		if(ProcCodeConstants.PROC_CODE_200E5010.equals(procCode)){//支付账户超限
        		            //调用service查询个人账户额度信息
        		            PersonTypeQuotaVo personTypeQuota = 
        		                    personIdUsedQuotaService.findPersonTypeQuota(userInfo.getCustId());
        		            mav.addObject("personTypeQuota", personTypeQuota);
                		}
                		if(ProcCodeConstants.PROC_CODE_200E5011.equals(procCode)){//支付验证方式超限
                			String[] dailyUsedQuata = personIdUsedQuotaService.findDailyUsedQuata(userInfo.getCustId(), getPayType(userInfo.getCustId()));
                			mav.addObject("dailyUsedQuata", dailyUsedQuata);
                		}
                	}
                }
         	}else{
         		CustCorpInfo payCust = custCorpInfoService.get(payCustId);
         		custName = payCust.getCorpName();
         	}
             mav.addObject("isRealNameCertify",isRealNameCertify);
        	 
        	if(StringUtils.equals(orderInfo.getIntTxnCd(), IntTxnCd._00200.value)){
        		//入金需要去掉国付宝支付的页签
        		if(payWay!=null && payWay.isSupport(PayChannelType.GFB_PAY.value)){
        			PayChannelDtlBean bean = payWay.getPayChannelDtl(PayChannelType.GFB_PAY.value);
        			payWay.getPayChannelList().remove(bean);
        		}
        		
            	//会员账户信息
                AcctMastBean bean = getInMoneyAcctBean(payCustId);
                
                if(bean ==null)
                	throw new WebException(ProcCodeConstants.PROC_CODE_100E3030);
                
                //入金计算手续费
        		PoundageRes p = getPoundageRes(order,getPayChannel());
        		if (null == p.getOrderFeePayer()) {
    	            logger.error("没有配置手续费承担方！no OrderFeePayer!" + p);
    	            throw new WebException(ProcCodeConstants.PROC_CODE_100E5051);
    	        }
        		orderInfo.setFeeAmt(f.format(p.getOrderRealFeeAmt()));
        		orderInfo.setFeePayer(p.getOrderFeePayer().value);
                orderInfo.setOrderAmt(f.format(p.getTotalAmt()));
            	//可用余额
            	BigDecimal avaAmt = new BigDecimal(bean.getAvaAmt());
            	mav.addObject("gopayAcctId", bean.getAcctId());
            	mav.addObject("avaAmt", f.format(avaAmt));
            	mav.addObject("custName", custName);

            	int avaFlag = 0;
            	//付款金额
            	BigDecimal payAmt = new BigDecimal(orderInfo.getOrderAmt());
            	if(avaAmt.compareTo(new BigDecimal(0))==0){
            		avaFlag = 3;
            	}else if(avaAmt.compareTo(payAmt)>-1){
            		avaFlag = 1;
            	}else{
            		avaFlag = 2;
            		//差额
            		BigDecimal shortfallPayAmt = payAmt.subtract(avaAmt);
            		mav.addObject("shortfallPayAmt", f.format(shortfallPayAmt));
            	}
            	mav.addObject("avaFlag", avaFlag);
            }else if(StringUtils.equals(orderInfo.getIntTxnCd(), IntTxnCd._00100.value) || StringUtils.equals(orderInfo.getIntTxnCd(), IntTxnCd._00400.value)
                    || StringUtils.equals(orderInfo.getIntTxnCd(), IntTxnCd._01813.value)){
            	List<AcctBean> accts = getAcctBeans(order, payCustId,AcctProd.GNST);
                if(accts!=null && accts.size()>0){
                    //默认显示第一个账户的余额
                    AcctBean firstAcct = accts.get(0);
                    mav.addObject("acctIds", accts);
                    mav.addObject("avaAmt", f.format(firstAcct.getAmout()));
                    mav.addObject("avaAmt2",firstAcct.getAmout());
                    mav.addObject("custName", custName);
                    mav.addObject("gopayAcctId",firstAcct.getAcctId());
                }
                //取已绑定的快捷银行卡
                mav.addObject("expressCardList",getExpressCardList());
            }else if(StringUtils.equals(orderInfo.getIntTxnCd(), IntTxnCd._01300.value) || StringUtils.equals(orderInfo.getIntTxnCd(), IntTxnCd._01302.value)){
                List<AcctBean> accts = getP2PAcctBeans(order);
                if(accts!=null && accts.size()>0){
                    //默认显示第一个账户的余额
                    AcctBean firstAcct = accts.get(0);
                    mav.addObject("acctIds", accts);
                    mav.addObject("avaAmt", f.format(firstAcct.getAmout()));
                    mav.addObject("custName", custName);
                }
            }
        }
        
        mav.addObject("formhash", setFormHashValue(request,order.getGopayOrderId()));// 防止hack
        //错误提示
        mav.addObject(FIELD_ERR_MSG,request.getSession().getAttribute(FIELD_ERR_MSG));
        request.getSession().removeAttribute(FIELD_ERR_MSG);
        //动态口令卡的提示
        mav.addObject("dcErrMesg", request.getSession().getAttribute("dcErrMesg"));
        request.getSession().removeAttribute("dcErrMesg");
        String loginEmail = getLoginEmail();
        mav.addObject("loginEmail", loginEmail);
        mav.addObject("cashier_url", CASHIER_URL);
        mav.addObject("cas_server_url", CAS_URL);
        mav.addObject("clientIp", RequestUtils.getRemoteRealIpAddr(request));
        mav.addObject("portal_url", PORTAL_URL);
        mav.addObject("sessionId",request.getSession().getId());
        mav.addObject("enable_fingerinfo",ENABLE_FINGERINFO);
        //登录错误返回
        int authErrorCount = getRequest().getSession().getAttribute("authErrorCount") == null ? 0: Integer.parseInt((String)getRequest().getSession().getAttribute("authErrorCount"));
        String casErrFlag = request.getParameter("casErrFlag");
        //<!--0 正常 1 常规校验错误  2 未审核通过 3 外部风控拒绝-->
        if(StringUtils.isNotBlank(request.getParameter("casErrMsg"))){
        	mav.addObject("casCustUserType", request.getParameter("casCustUserType"));
        	mav.addObject("casErrMsg", request.getParameter("casErrMsg"));
        	mav.addObject("casErrFlag",casErrFlag);
            authErrorCount = authErrorCount +1;
            getRequest().getSession().setAttribute("authErrorCount",authErrorCount+"");
            //快捷支付 获取登录密码错误次数--2次及以上显示验证码
            if(authErrorCount>=2){
                mav.addObject("authDisplay","1");
            }
            ch = "06";
        }else{
            getRequest().getSession().removeAttribute("authErrorCount");
        }
        mav.setViewName(getViewName(order.getGopayIntTxnCd()));
        if(StringUtils.equals(order.getGatewaySource(), GatewaySource.GATEWAY_SOURCE_09.value)){
        	mav.setViewName("gsrt/payOrder");
        	//mav.addObject("userType", loginUser.getUser().getUserType());
        	GopayAllCustInfo payCust = allCustInfoQueryDAO.getAllCustInfoByCustId(order.getPayCustId());
        	mav.addObject("userType", payCust.getCustType());
        	mav.addObject("incUrl", "javascript:history.go(-1);");
        }
        mav.addObject("orderKey",getOrderKey(order.getGopayOrderId()));
        mav.addObject("ch", ch);
        
        
        //快捷支付 身份验证版update  by dongdh 20160317
        
        if (transDtl != null ) {
        	
        	if (StringUtils.isNotEmpty(transDtl.getBuyerRealBankAcctNum())) {
        		logger.info("平台上送银行账号，处理卡bin信息");
        		
        		//判断卡号状态
        		String ccardNo = transDtl.getBuyerRealBankAcctNum().replaceAll(" ","");
                boolean res = epBankCardService.isFreezeCardNo(ccardNo);
        		if (res) {
        			/**
            		 * modified by zyt 对日志卡号做掩码显示
            		 * 2017-1-13
            		 */
        			logger.info("平台上送银行卡已被冻结cardno=" + LoggerMaskUtils.maskString(ccardNo));
        			//logger.info("平台上送银行卡已被冻结cardno=" + ccardNo);
        			throw new WebException(ProcCodeConstants.PROC_CODE_100E5118);
        		}
        		
        		//如果上送的银行卡号 不为空  ， 先判断卡bin
        		EpCardBin cardBin = epBankCardService.getEpCardBinByCardNo(transDtl.getBuyerRealBankAcctNum());
        		if (cardBin != null) {
        			//找到bin 则直接跳转到 快捷支付的第二步, 没找到 不处理
        			
        			/*EpCardType cardType = cardBin.getCardType();
        			if (cardType.value != 0) {
        				//非借记卡
        				logger.error("该版本网关支付不支持信用卡付款orderId=" + order.getGopayOrderId());
        	            throw new WebException(ProcCodeConstants.PROC_CODE_100E6085);
        			}*/
        			
        			Map<String, Object> model = new HashMap<>();
        			model.put("pageFrom", "order");
        			
        			if (cardBin.getCardType().value == 0) {
        				model.put("exPayChannel", PayChannel._03.value);
        			} else if (cardBin.getCardType().value == 1) {
        				model.put("exPayChannel", PayChannel._06.value);
        			}
        			
        			model.put("exPayBankCode", cardBin.getBinBankCode());
        			///mav.addObject("exGopayAcctId", bean.getAcctId());
        			
        			model.put("exPayWay", BankPayWay.F); //银行卡全额支付
                	
                	model.put("exIdCardNo", transDtl.getBuyerRealCertNo());
                	model.put("exHolder", transDtl.getBuyerRealName());
                	model.put("exMobileNo", transDtl.getBuyerRealMobile());
                	
                	model.put("bankCardNo", transDtl.getBuyerRealBankAcctNum());
                	
                	model.put(GOPAY_ORDER_ID, order.getGopayOrderId());
                	model.put("orderKey", getOrderKey(order.getGopayOrderId()));
        			//返回view
                	String url = "/00100/express/location.shtml";
                	RedirectView view = new RedirectView(url, true);
                	
        			logger.info("转发到/location.shtml页面");
        			
					return new ModelAndView(view, model);
        		} else {
        			/// 还是跳转到原页面  但是需要隐藏 其他标签
        			mav.addObject("bankAcctNum", transDtl.getBuyerRealBankAcctNum());
        			mav.addObject("onlyExp", "true"); //只留快捷交易的标签
        		}
        	}

        	/*if (StringUtils.isNotBlank(transDtl.getBuyerRealCertNo())
        			&& StringUtils.isNotBlank(transDtl.getBuyerRealName())) {
        		//如果 上送姓名和身份证号 同时存在 则认为 也是 只做快捷交易
        		mav.addObject("onlyExp", "true");
        	}*/
        	
        }
        // 账户支付新增扫码支付功能 add by liyang 20171130 START
        String url;
        if(walletAppUrl.indexOf("?") > -1) {
            url = walletAppUrl + "&orderid=" + order.getGopayOrderId();
        } else {
            url = walletAppUrl + "?orderid=" + order.getGopayOrderId();
        }
        Map<String,Integer> size = new HashMap<>(2);
        size.put("width",220);
        size.put("height",220);
        String imageBase64QRCode = QRCodeUtil.createQRCode(url,size);
        mav.addObject("imageBase64QRCode",imageBase64QRCode);
        // liyang 20171130 END
        return mav;
    }

    /**
     * 仅入金登录
     * @param ch
     * @return
     * @throws WebException
     */
    @RequestMapping("/sec/pay/info.shtml")
    public ModelAndView secPayInfo(String ch) throws WebException{
    	ModelAndView mav = new ModelAndView();
    	String newUrl = "/pay/info.shtml";
    	try {
    		 LoginUser loginUser = getLoginUser();
    		 String gopayUser = getGopayUser();
             String orderId = getRequest().getParameter("orderId");
    		 if(StringUtils.isNotBlank(gopayUser) && loginUser!=null){
                CpsGenMainOrder order = getMainOrder(orderId, true);
                String loginEmail = getLoginEmail();
                Decrypt de = new Decrypt("_gopay_user");
                String user =  de.decrypt(gopayUser);
                mav.addObject("ch", ch);
                mav.addObject("loginEmail", loginEmail);
                mav.addObject("orderId",orderId);
                mav.addObject("orderKey",getOrderKey(orderId));
                if((!StringUtils.equals(user, loginEmail) || user==null) && StringUtils.equals(order.getGopayIntTxnCd(), IntTxnCd._00200.value) ){
                    SecurityUtils.getSubject().logout();
                    mav.setViewName("redirect:"+newUrl);
                    return mav;
                }
            }
            if(loginUser != null){
                //补全用户信息
                CustPersonInfo  custInfo =  custPersonInfoQueryManager.get(loginUser.getUser().getCustId());
                if(custInfo != null){
                    if(StringUtils.equals(custInfo.getCustStat(), CustPersonInfoConstants.CUST_STAT_NORMAL) && StringUtils.isBlank(custInfo.getPayPwd())){
                        OrderInfo orderInfo = getOrderInfo(getRequest().getParameter("orderId"));
                        getRequest().getSession().setAttribute("fillInfoCustId",loginUser.getUser().getCustId());
                        mav.addObject("order",orderInfo);
                        mav.addObject("custId",loginUser.getUser().getCustId());
                        mav.addObject("orderId",getRequest().getParameter("orderId"));

                        mav.setViewName("00100/content/express/completeInfo");
                        mav.addObject("profession", dicCustProfessionQueryManager.getAll());//职业
                        mav.addObject("questionList", PayPwdQuestionsInfo.getNewQuestionList());//问题
                        mav.addObject("type","2");
                        return mav;
                    }
                }
            }
    		mav.setViewName("forward:"+newUrl);
  		} catch (Exception e) {
  			e.printStackTrace();
  		}
    	return mav;
    }
    
    
    
    @RequestMapping("/sec/pay/getAvaAmt.shtml")
    @ResponseBody
    public String getAvaAmt(String acctId) throws WebException{
    	if(StringUtils.isBlank(acctId))
    		return "";
    	
    	AcctMastBean bean = acctTransService.getAccount(acctId);
    	if(bean!=null){
    		JSONObject json = new JSONObject();
    		json.accumulate("avaAmt", new DecimalFormat("0.00").format(new BigDecimal(bean.getAvaAmt())));
    		return json.toString();
    	}
    	return "";
    }
    
    private ModelAndView ipCheckDecison(PayInfoCommand command, CpsGenMainOrder order)
            throws WebException {
        String ipCheckDecison = command.getIpCheckDecison();
        
        // 这种情况直接返回null，跳过反钓鱼处理。
        if (!YnFlag.y.code.equals(ipCheckDecison) && !YnFlag.n.code.equals(ipCheckDecison)) return null;
        
        RcsAntiPhishViolateLog log = rcsAntiPhishingViolateLogManager.getByTransDtlSq(order.getTransDtlSq());
        if (null == log) {
            logger.error("反钓鱼日志不存在！RcsAntiPhishViolateLog not exist!" + command);
            throw new WebException(ProcCodeConstants.PROC_CODE_100E5041);
        }
        if (YnFlag.n.code.equals(ipCheckDecison)) {// 反钓鱼-用户选择终止支付
            log.setUserDicision(UserDicision.STOP.code);
            rcsAntiPhishingViolateLogManager.update(log);
            return new ModelAndView("common/close");
        }else if (YnFlag.y.code.equals(ipCheckDecison)) {// 反钓鱼-用户选择继续支付
            log.setUserDicision(UserDicision.CONTINUE.code);
        }
        return null;
    }

    private ModelAndView directBankPayPage(PayInfoCommand command) throws WebException {
        logger.error("直连银行支付 BankRequestController.directBankPayPage " + command);
        // 重新查询订单，状态为最新的
        CpsGenMainOrder order = getMainOrder(getOrderId(), true);
        String userType = "";
        PayChannel payChannel = null;
        if (PayChannel._01.value.equals(order.getPayChannel())) {
            userType = "1";
            payChannel = PayChannel._01;
        }
        else if (PayChannel._51.value.equals(order.getPayChannel())) {
            userType = "2";
            payChannel = PayChannel._51;
        }
        else {
            logger.error("错误的付款通道类型！wrong PayChannel!" + order);
            throw new WebException(ProcCodeConstants.PROC_CODE_100E5006);
        }
        ModelAndView mav = new ModelAndView("pay/bankPayForBis");
        OrderInfo orderInfo = getOrderInfo(order.getGopayOrderId());
        
        /**系统加固   发送BIS交易金额  1.首先获取结算金额  2.结算金额无值，取总金额     zhg.zhang 20160712 start**/
        
        BigDecimal amount=order.getSettleAmt()!=null
        		&&NumberUtils.isLargerThan(order.getSettleAmt(),BigDecimal.ZERO )
        		?order.getSettleAmt():order.getTotalOrderAmt();
        logger.info("order settleAmt="+order.getSettleAmt()+""
        		+ ",totalOrderAmt="+order.getTotalOrderAmt()+",orderId="+order.getGopayOrderId());
        /**系统加固   发送BIS交易金额  1.首先获取结算金额  2.结算金额无值，取总金额     zhg.zhang 20160712 end**/
        
        
        mav.addObject("orderId", order.getGopayOrderId());
//        mav.addObject("amount", order.getTotalOrderAmt());
        mav.addObject("amount", amount);
        mav.addObject("orderDate", DateUtils.format(order.getGopayTxnTm()));
        mav.addObject("userType", userType);
        mav.addObject("bank", order.getOutStlmId());
        mav.addObject("order", orderInfo);
        mav.addObject("bisUrl", CashierConfig.get(CashierConfig.BIS_URL));
        mav.addObject("bankBusProd", BisBankBusinessProdConvertUtil.getBisBankBusinessProd(payChannel).value);
        //银行客户号
        setB2BBankConfig(mav,PayChannel.get(order.getPayChannel()),order.getOutStlmId());

        logger.info("MAV : " + mav.getViewName() );
        return mav;
    }

    private void updateDirectBankPayOrder(PayInfoCommand command, CpsGenMainOrder order) throws WebException {
        // 调用cps更新订单状态为:出款清算单位处理中
        Map<MainOrderField, String> values = new HashMap<MainOrderField, String>();
        PayChannel payChannel = null;
        if (PayChannel._01.value.equals(order.getPayChannel())) {
            payChannel = PayChannel._01;
        }
        else if (PayChannel._51.value.equals(order.getPayChannel())) {
            payChannel = PayChannel._51;
        }else {
            logger.error("错误的付款通道类型！wrong PayChannel!" + order);
            throw new WebException(ProcCodeConstants.PROC_CODE_100E5006);
        }
        //update by jianghoup  直连银行的银行代码添加
        PoundageRes p = getPoundageRes(order,payChannel,order.getOutStlmId());
        values.put(MainOrderField.ORDER_DEAL_AMT, p.getOrderDealAmt().toString());
        values.put(MainOrderField.ORDER_REAL_FEE_AMT, p.getOrderRealFeeAmt().toString());
        values.put(MainOrderField.TOTAL_ORDER_AMT, p.getTotalAmt().toString());
        values.put(MainOrderField.TOTAL_ORDER_FEE_AMT, p.getTotalFeeAmt().toString());
        values.put(MainOrderField.TXN_STA_CD, TxnStaCode.TXN_STA_CD_30101.value + "");
        
        /**结算金额： 网银付款更新结算金额字段  系统加固   zhg.zhang 20160712 start**/
        values.put(MainOrderField.SETTLE_AMT, p.getSettleAmt().toPlainString());
        /**结算金额： 网银付款更新结算金额字段  系统加固   zhg.zhang 20160712 end**/
        
        
        // 如果是收款方承担手续费，且手续费金额大于订单金额，中断交易，防止实际交易金额为负数。
        if (OrderFeePayer.REC_PAYER.equals(p.getOrderFeePayer())) {
            if (1 == p.getTotalFeeAmt().compareTo(order.getMerTxnAmt())) {
                logger.error("手续费金额大于订单金额，中断交易！pay error: feeAmt[" + p.getTotalFeeAmt() + "]>merTxnAmt["
                        + order.getMerTxnAmt() + "]! " + command + ", " + order);
                throw new WebException(ProcCodeConstants.PROC_CODE_100E5055);
            }
        }

        //懒猫接口扣除手续费的普通账户如果账户可用余额小于手续费，则抛出异常，账户余额不足 add by liuyong 20170209
        if (IntTxnCd._00100.value.equals(order.getGopayIntTxnCd())//通过交易码和网关来源来判断是懒猫接口
                &&GatewaySource.GATEWAY_SOURCE_17.value.equals(order.getGatewaySource()) ){
            List<AcctMastBean>  accts = acctTransService.getAccounts(order.getMainRecvCustId());
            Collections.sort(accts, new Comparator<AcctMastBean>() {
                @Override
                public int compare(AcctMastBean o1, AcctMastBean o2) {
                    return o1.getAcctId().compareTo(o2.getAcctId());
                }
            });
            AcctMastBean gnstAcct = null;
            for(AcctMastBean acctMastBean :accts){
                if(AcctProd.GNST.equals(acctMastBean.getProdCode())){
                    gnstAcct = acctMastBean;
                    break;
                }
            }
            if (new BigDecimal(gnstAcct.getAvaAmt()).compareTo(p.getTotalFeeAmt())<0){
                logger.error("手续费金额大于普通账户可用余额，中断交易，支付失败，请联系平台！pay error: feeAmt[" + p.getTotalFeeAmt() + "]>avaAmt["
                        + gnstAcct.getAvaAmt() + "]! " + command + ", " + order);
                throw new WebException(ProcCodeConstants.PROC_CODE_100E5344);
            }
        }
        // 云账户子账户收款交易如果普通账户可用余额小于手续费，则抛出异常，账户余额不足 add by sh.jiao 20171020
        if(IntTxnCd._01813.value.equals(order.getGopayIntTxnCd())) {
            AcctMastBean acct = acctTransService.getAccount(order.getMainRecvAcct());
            if(acct == null) {
                logger.error("收款账户不存在,gopayOrderId:"+order.getGopayOrderId());
                throw new WebException(ProcCodeConstants.PROC_CODE_100E5260);
            }
            if (new BigDecimal(acct.getAvaAmt()).compareTo(p.getTotalFeeAmt())<0){
                logger.error("手续费金额大于普通账户可用余额，中断交易，支付失败，请联系平台！pay error: feeAmt[" + p.getTotalFeeAmt() + "]>avaAmt["
                        + acct.getAvaAmt() + "]! " + command + ", " + order);
                throw new WebException(ProcCodeConstants.PROC_CODE_100E5344);
            }
        }


        try {
            logger.error("调用cps更新直连银行订单状态.BEGIN.call cps to update DirectBankPay order" + command + ", " + order + ", "
                    + values);
            mainOrderUpdateService.updateMany(order.getGopayOrderId(), values);
            //如果是G商融通的充值，则去更新G商融通充值业务表
            if(StringUtils.equals(order.getGatewaySource(), GatewaySource.GATEWAY_SOURCE_09.value)){
            	gsrtService.updateGsrtRecharge(order.getGopayOrderId());
            }
            logger.error("调用cps更新直连银行订单状态.END.call cps to update DirectBankPay order" + command + ", " + order);
        } catch (GopayException e) {
            logger.error("调用cps更新直连银行订单状态出错！call cps to update DirectBankPay order error!" + command + ", " + order, e);
            throw new WebException(e.getErrCode());
        }
    }

    private AcctMastBean getInMoneyAcctBean(String custId){
    	List<AcctMastBean>  accts = acctTransService.getAccounts(custId);
    	if(accts!=null && accts.size()>0){
    		for(AcctMastBean bean : accts){
        		if(bean.getProdCode() == AcctProd.BLME){
        			return bean;
        		}
        	}
    	}
    	return null;
    }
    /**
     * G商融通获取商户平台账户
     * @param merId
     * @return
     */
    private AcctMastBean getPTAcctBean(String merId){
    	List<AcctMastBean>  accts = acctTransService.getAccounts(merId);
    	if(accts!=null && accts.size()>0){
    		for(AcctMastBean bean : accts){
        		if(bean.getProdCode() == AcctProd.GTPTZH){
        			return bean;
        		}
        	}
    	}
    	return null;
    }
    
    private void validate(PayInfoCommand command, CpsGenMainOrder order, CustCorpInfo cust)
            throws WebException {
        if (null == order) {
            logger.error("订单不存在！order not exist!" + command);
            throw new WebException(ProcCodeConstants.PROC_CODE_100E5041);
        }
        if (null == cust) {
            logger.error("商户不存在！cust not exist!" + command);
            throw new WebException(ProcCodeConstants.PROC_CODE_100E5001);
        }
        /*if (!"1".equals(cust.getIsRealNameCertify())) {
            logger.error("商户未通过实名认证！mer IsRealNameCertify != 1!" + order);
            throw new WebException(ProcCodeConstants.PROC_CODE_100E2031);
        }*/
        // 只有挂起状态的订单才能继续支付
        // 如果允许08状态的订单重新发起，由于OUT_STLM_ID有值了，会误判为直连银行
        if (TxnStaCode.TXN_STA_CD_30000.value != (order.getTxnStaCd())) {
            logger.error("订单状态不对！txn_sta_cd wrong!" + order);
            throw new WebException(ProcCodeConstants.PROC_CODE_100E5042);
        }
    }

    private PayChannel getPayChannel(){
        LoginUser userInfo = getLoginUser();
        UserType userType = UserType.get(userInfo.getUser().getUserType());
        PayChannel payChannel = null;
        if (UserType.Person.equals(userType)) {
            payChannel = PayChannel._02;
        } else {
            payChannel = PayChannel._52;
        }
        return payChannel;
    }

    private String getViewName(String intTxnCd){
        if(StringUtils.equals(intTxnCd, IntTxnCd._00100.value)
                || StringUtils.equals(intTxnCd, IntTxnCd._01813.value)){
            return "00100/index";
        }else{
            return "pay/payOrder";
        }
    }

    private List<ExpressCardInfo> getExpressCardList(){
        List<EpCardBindInfoVo> cardList = epBankCardService.getBindCardInfoVoByCustId(getLoginUser().getUser().getCustId());
        if(cardList == null || cardList.size() == 0)
            return null;
        List<ExpressCardInfo> cardInfos = new ArrayList<ExpressCardInfo>();
        for(EpCardBindInfoVo info : cardList){
            ExpressCardInfo ec = new ExpressCardInfo();
            ec.setCardId(info.getSq());
            ec.setBankCardNo(info.getBankAcctNum());
            ec.setExMobileNo(info.getBindMobile());
            ec.setExHolder(info.getBankAcctName());
            ec.setExPayBankCode(info.getBankCode());
            ec.setExIdCardNo(info.getCertNo());
            PayChannel cardPaych = StringUtils.equals(info.getCardType(),EpCardBindInfoVo.CARD_TYPE_CREDIT) ? PayChannel._06 :PayChannel._03;
            ec.setExPayChannel(cardPaych.value);
            if(cardPaych == PayChannel._06)
                ec.setExValidDate(info.getCreditCardExpired());
            	//ec.setExValidDate(DateUtils.format(info.getCreditCardExpired(),"MMyy"));
            cardInfos.add(ec);
        }
        return cardInfos;
    }
    
    //返回三类账户是否超限的方式
    public String getCheckThreeCode(String userId,String custId,BigDecimal orderAmt){
    	String payType= getPayType(custId);
        //返回处理码
        String procCode=personIdentifyManager.getIdentityLimitCheck(userId, orderAmt, payType,IntTxnCd._00100.value);
        if(ProcCodeConstants.PROC_CODE_200S1000.equals(procCode)){
        	return null;
        }else{
        	return procCode;
        }
    }
    
    //获取支付验证方式
    private String getPayType(String custId){
    	String payType=PayAuthType.one.value;//支付密码
        if(userDcPwdManager.getDCAuth(custId)){ //支付密码+其他(动态口令卡)
            payType=PayAuthType.three.value;
        }else{//支付密码+数字证书(电子签名)的校验
            CustCaCert custCaCert = caCertService.getCustCaCertByCustId(custId);
            if(null != custCaCert && CustCaCertConstants.CUST_CA_CERT_STAT_ACTIVE.equals(custCaCert.getStat())){
                payType=PayAuthType.two.value; 
            }
        }
        return payType;
    }
    
    @RequestMapping(value="/sec/logined",method = RequestMethod.POST)
    @ResponseBody
    public void logged(){
        LoginUser loginUser = getLoginUser();
        UserInfo userInfo = userInfoService.get(loginUser.getUser().getUserId());
        userInfo.setIsFirstLogin(UserInfoConstants.NOT_FIRST_LOGIN);
        userRemoteService.editUserInfo(userInfo);
        SecurityUtils.getSubject().getSession().setAttribute("isFirstLogin", UserInfoConstants.NOT_FIRST_LOGIN);
    }
    
}
